package com.fowo.api.documentCirculation.util;

import com.fowo.api.common.util.SheetUtils;
import lombok.experimental.UtilityClass;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * 数值处理工具类
 * @author yl_ls
 */
@UtilityClass
public class NumberUtil {

    /**
     * 比较两个数值类型的大小
     * @param num1 第一个数值
     * @param num2 第二个数值
     * @return 第一个数值大于第二个数值返回 1，第二个数值大于第一个数值返回 -1，相等返回 0。
     */
    public int compareTo(Object num1, Object num2) {
        Number d1 = asNumber(num1);
        Number d2 = asNumber(num2);
        if (d1 instanceof Long) {
            return ((Long) d1).compareTo(d2.longValue());
        }
        if (d1 instanceof Integer) {
            return ((Integer) d1).compareTo(d2.intValue());
        }
        if (d1 instanceof Double) {
            return ((Double) d1).compareTo(d2.doubleValue());
        }
        if (d1 instanceof Float) {
            return ((Float) d1).compareTo(d2.floatValue());
        }
        if (d1 instanceof BigDecimal) {
            return ((BigDecimal) d1).compareTo(new BigDecimal(d2.toString()));
        }
        throw new UnsupportedOperationException("num1 is unsupported type");
    }

    /**
     * 输入转换为数字类型（不可转换的情况会返回 0）
     * @param obj 输入类型
     * @return 转换后值
     */
    public static Number asNumber(Object obj) {
        if (obj instanceof Number) {
            return (Number) obj;
        }
        if (obj instanceof String) {
            return new BigDecimal((String) obj);
        }
        return 0;
    }

    /**
     * 两个数据相加
     * @param num1 第一个数值
     * @param num2 第二个数值
     * @return 相加后的值，类型与第一个数值相同，如果第一个值为 null，直接返回第二个值
     */
    public Number add(Number num1, Number num2) {
        if (num1 instanceof Integer) {
            return addInteger((Integer)num1, num2);
        }
        if (num1 instanceof Long) {
            return addLong((Long)num1, num2);
        }
        if (num1 instanceof BigDecimal) {
            return addDecimal((BigDecimal)num1, num2);
        }
        if (num1 == null) {
            return num2;
        }
        throw new RuntimeException("不支持的数值类型计算");
    }

    /**
     * 两个数据相减
     * @param num1 第一个数值
     * @param num2 第二个数值
     * @return 相减后的值，类型与第一个数值相同
     */
    public Number subtract(Number num1, Number num2) {
        if (num1 instanceof Integer) {
            return subtractInteger((Integer)num1, num2);
        }
        if (num1 instanceof Long) {
            return subtractLong((Long)num1, num2);
        }
        if (num1 instanceof BigDecimal) {
            return subtractDecimal((BigDecimal)num1, num2);
        }
        throw new RuntimeException("不支持的数值类型计算");
    }

    /**
     * 两个数据相乘
     * @param num1 第一个数值
     * @param num2 第二个数值
     * @return 相乘后的值，类型与第一个数值相同
     */
    public Number multiply(Number num1, Number num2) {
        if (num1 instanceof Integer) {
            return multiplyInteger((Integer)num1, num2);
        }
        if (num1 instanceof Long) {
            return multiplyLong((Long)num1, num2);
        }
        if (num1 instanceof BigDecimal) {
            return multiplyDecimal((BigDecimal)num1, num2);
        }
        throw new RuntimeException("不支持的数值类型计算");
    }

    private static Number multiplyDecimal(BigDecimal num1, Number num2) {
        if (num2 instanceof Integer) {
            return num1.multiply(BigDecimal.valueOf((Integer) num2));
        }
        if (num2 instanceof Long) {
            return num1.multiply(BigDecimal.valueOf((Long) num2));
        }
        if (num2 instanceof BigDecimal) {
            return num1.multiply((BigDecimal) num2);
        }
        throw new RuntimeException("不支持的数值类型计算");
    }

    private static Number multiplyLong(Long num1, Number num2) {
        return num1 * num2.longValue();
    }

    private static Number multiplyInteger(Integer num1, Number num2) {
        return num1 * num2.intValue();
    }

    private static Number subtractDecimal(BigDecimal num1, Number num2) {
        if (num2 instanceof Integer) {
            return num1.subtract(BigDecimal.valueOf((Long) num2));
        }
        if (num2 instanceof Long) {
            return num1.subtract(BigDecimal.valueOf((Long) num2));
        }
        if (num2 instanceof BigDecimal) {
            return num1.subtract((BigDecimal) num2);
        }
        throw new RuntimeException("不支持的数值类型计算");
    }

    private static Number subtractLong(Long num1, Number num2) {
        return num1 - num2.longValue();
    }

    private static Number subtractInteger(Integer num1, Number num2) {
        return num1 - num2.intValue();
    }

    private static BigDecimal addDecimal(BigDecimal num1, Number num2) {
        if (num2 instanceof Integer) {
            return num1.add(BigDecimal.valueOf((Long) num2));
        }
        if (num2 instanceof Long) {
            return num1.add(BigDecimal.valueOf((Long) num2));
        }
        if (num2 instanceof BigDecimal) {
            return num1.add((BigDecimal) num2);
        }
        throw new RuntimeException("不支持的数值类型计算");
    }

    private static Long addLong(Long num1, Number num2) {
        return num1 + num2.longValue();
    }

    private static Integer addInteger(Integer num1, Number num2) {
        return num1 + num2.intValue();
    }

    public static BigDecimal toDecimal(Object number) {
        if (number instanceof BigDecimal) {
            return (BigDecimal) number;
        }
        if (number instanceof Integer) {
            return BigDecimal.valueOf((int)number);
        }
        if (number instanceof Long) {
            return BigDecimal.valueOf((long)number);
        }
        if (number instanceof String) {
            return SheetUtils.toDecimal((String)number);
        }
        throw new RuntimeException("不支持的数值类型转换");
    }

    public static Long toLong(Object obj) {
        if(Objects.isNull(obj)) {
            return null;
        }
        if (obj instanceof Number) {
            return ((Number)obj).longValue();
        }
        if (obj instanceof String) {
            return SheetUtils.toLong((String)obj);
        }
        throw new RuntimeException("不支持的数值类型转换");
    }
}
